package com.ruoyi.web.controller.product;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Tuple;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.biz.ResultSaveModule;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.web.server.entity.ResultSave;
import com.ruoyi.web.server.service.ResultSaveService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;


/**
 * <p>
 *  大气风场通用接口集合
 * </p>
 *
 * @author liuhl
 * @since 2024-04-15
 */
@RestController
@RequestMapping("/product")
@AllArgsConstructor
@Slf4j
@Api(tags = "产品数据管理")
public class ProductManageController {

    private ResultSaveService resultSaveService;


    @GetMapping("/query")
    @ApiOperation(value = "查询", notes = "产品数据查询", httpMethod = "GET")
    public AjaxResult query(@RequestParam Map<String,Object> paramMap) {

        //1.过滤参数中的value空值
        Iterator<Map.Entry<String, Object>> iterator = paramMap.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry<String, Object> entry = iterator.next();
            Object value = entry.getValue();
            if (value == null || StrUtil.isBlank(value.toString())){
                iterator.remove();
            }
        }

        paramMap.remove("rdtmp"); //这是前端用来消除浏览器缓存的一个对业务无用字段

        Integer pageNum = Integer.valueOf(paramMap.get("pageNum").toString());
        paramMap.remove("pageNum");
        Integer pageSize =Integer.valueOf(paramMap.get("pageSize").toString());
        paramMap.remove("pageSize");

        String module = paramMap.get("module").toString();
        paramMap.remove("module");
        String submodule = paramMap.get("submodule").toString();
        paramMap.remove("submodule");



        String startTime = paramMap.get("startTime") == null ? null : paramMap.get("startTime").toString();
        paramMap.remove("startTime");
        String endTime = paramMap.get("endTime") == null ? null : paramMap.get("endTime").toString();
        paramMap.remove("endTime");

        String fileName = paramMap.get("fileName") == null ? null : paramMap.get("fileName").toString();
        paramMap.remove("fileName");

        String paramsLike = paramMap.entrySet().stream()
                .filter(o -> o.getValue() != null)
                .map(o -> o.getKey() + Constants.ENTRY_D + o.getValue())
                .sorted()
                .collect(Collectors.joining("%","%","%"));

        //select * from PIESAT_DGDQ.RESULT_SAVE where 1=1
        //and PARAMS like '%satellite::::[SWDATA_OBS_DEN_SWARMB, SWDATA_OBS_DEN_SWARMA]%relative_error=22.69±6.20%'
        //and start_time <= '2014-01-01'
        //and '2014-02-01' <=  end_time
        //and MODULE = 'MODEL_ASSESS'
        //and SUBMODULE = 'MODEL_ASSESS_ALT';

        Page<ResultSave> page = resultSaveService.page(
                new Page<>(pageNum, pageSize),
                new LambdaQueryWrapper<ResultSave>()
                        .eq(ResultSave::getModule, module)
                        .eq(ResultSave::getSubmodule, submodule)
                        .ge(StrUtil.isNotBlank(startTime), ResultSave::getCreateTime, startTime)
                        .le(StrUtil.isNotBlank(endTime), ResultSave::getCreateTime, endTime)
                        .like(StrUtil.isNotBlank(paramsLike), ResultSave::getParams, paramsLike)
                        .like(StrUtil.isNotBlank(fileName), ResultSave::getFileNames, fileName)
                        .orderByDesc(ResultSave::getCreateTime)
        );

        page.getRecords().forEach(entity -> {
            Map<String, String> paramJson = Arrays.stream(entity.getParams().split(Constants.FIELD_D)).collect(Collectors.toMap(
                    entry -> entry.split(Constants.ENTRY_D)[0],
                    entry -> StrUtil.isBlank(entry.split(Constants.ENTRY_D)[1])?"":entry.split(Constants.ENTRY_D)[1]
            ));
            entity.setParamJson(paramJson);
        });

        return AjaxResult.success(page);
    }

    @PostMapping("/download")
    @ApiOperation(value = "批量下载", notes = "下载产品结果文件", httpMethod = "POST")
    public void downloadBatch(@RequestBody List<Long> ids, HttpServletResponse response) throws IOException {
        InputStream[] finalInputStreamArr = null;
        try {
            List<ResultSave> list = resultSaveService.list(new LambdaQueryWrapper<ResultSave>()
                    .select(ResultSave::getResultData,ResultSave::getSubmodule,ResultSave::getCreateTime)
                    .in(ResultSave::getId, ids)
            );
            if (CollUtil.isEmpty(list)){
                throw new RuntimeException("查询不到相关数据");
            }
            String submoduleName = ResultSaveModule.getSubmoduleName(list.get(0).getSubmodule());
            //每一个实体都要打个zip包
            List<Tuple> zipNameAndInputStreamTupleList = Collections.synchronizedList(new ArrayList<Tuple>());
            List<CompletableFuture<Void>> futures = list.stream().map(o -> {
                return CompletableFuture.runAsync(() -> {

                    //每个文件的路径
                    List<String> resultDataList = JSONUtil.parseArray(o.getResultData())
                            .toList(String.class)
                            .stream()
                            .distinct()
                            .collect(Collectors.toList());

                    //每个文件的名字需要变化一下，因为动态修正那块有文件名相同的情况发生
                    String[] fileNames = resultDataList.stream().map(filePath -> {
                        return IdUtil.fastSimpleUUID().substring(0,6) + filePath.substring(filePath.lastIndexOf("/") + 1);
                    }).toArray(String[]::new);

                    //每个文件的输入流
                    InputStream[] isArray = null;
                    try {
                        isArray = resultDataList.stream().map(name -> {
                            File file = new File(name);
                            if (!file.exists()){
                                log.info("参数 name :{} 指向的文件: {} 不存在", name, file.getAbsolutePath());
                            }
                            try {
                                return new FileInputStream(file);
                            } catch (FileNotFoundException e) {
                                throw new RuntimeException(e);
                            }
                        }).toArray(InputStream[]::new);
                        // 压缩至输出流
                        ByteArrayOutputStream out = new ByteArrayOutputStream();
                        ZipUtil.zip(out, fileNames, isArray);

                        String zipName = DateUtil.format(o.getCreateTime(), DatePattern.PURE_DATETIME_FORMAT) + ".zip";
                        InputStream inputStream = new ByteArrayInputStream(out.toByteArray());
                        zipNameAndInputStreamTupleList.add(new Tuple(zipName, inputStream));
                    }catch (Exception e){
                        e.printStackTrace();
                        throw new RuntimeException(e.getMessage());
                    }finally {
                        if (isArray != null){
                            Arrays.asList(isArray).forEach(is -> {
                                try {
                                    is.close();
                                } catch (IOException e) {
                                    throw new RuntimeException(e);
                                }
                            });
                        }
                    }
                });
            }).collect(Collectors.toList());
            //阻塞
            CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).join();

            String[] zipNames = zipNameAndInputStreamTupleList.stream().map(o -> o.get(0)).toArray(String[]::new);
            finalInputStreamArr = zipNameAndInputStreamTupleList.stream().map(o -> o.get(1)).toArray(InputStream[]::new);

            //文件下载
            String zipAllName = submoduleName + "_" + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_FORMAT) + ".zip";
            FileUtils.setAttachmentResponseHeader(response, zipAllName);
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            OutputStream os = response.getOutputStream();

            ZipUtil.zip(os, zipNames, finalInputStreamArr);
        }catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }finally {
            if (response.getOutputStream() != null){
                response.getOutputStream().close();
            }
            if (finalInputStreamArr != null){
                Arrays.asList(finalInputStreamArr).forEach(is -> {
                    try {
                        is.close();
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                });
            }
        }
    }




    public static void main(String[] args) throws Exception{

        String pathDiagram1 = "E:\\testWord\\diagram1.png";
        String pathDiagram2 = "E:\\testWord\\diagram2.png";

        String zip1Path= "E:\\testWord\\zip-diagram.zip";
        String zip2Path= "E:\\testWord\\zip-result.zip";
        String zipAllPath= "E:\\testWord\\zip-all.zip";

        List<String> pathList1 = CollUtil.newArrayList(pathDiagram1, pathDiagram2);

        InputStream[] inputStreams1 = pathList1.stream().map(name -> {
            try {
                return new FileInputStream(name);
            } catch (FileNotFoundException e) {
                throw new RuntimeException(e);
            }
        }).toArray(InputStream[]::new);

        String[] names1 = {"diagram1-0.png", "diagram2-0.png"};
        // 创建输出流
        ByteArrayOutputStream out1 = new ByteArrayOutputStream();

        // 压缩文件
        ZipUtil.zip(out1, names1, inputStreams1);

//         //将压缩后的数据写入文件或者作为流传输
//         FileOutputStream fos = new FileOutputStream(zip1Path);
//         out.writeTo(fos);
//         fos.close();


        String result1 = "E:\\testWord\\test_result.txt";
        String result2 = "E:\\testWord\\response.json";

        List<String> pathList2 = CollUtil.newArrayList(result1, result2);


        InputStream[] inputStreams2 = pathList2.stream().map(name -> {
            try {
                return new FileInputStream(name);
            } catch (FileNotFoundException e) {
                throw new RuntimeException(e);
            }
        }).toArray(InputStream[]::new);

        String[] names2 = {"test_result-0.txt", "response-0.json"};
        // 创建输出流
        ByteArrayOutputStream out2 = new ByteArrayOutputStream();

        // 压缩文件
        ZipUtil.zip(out2, names2, inputStreams2);


        //集体压缩
        // 转换为InputStream
        InputStream is1 = new ByteArrayInputStream(out1.toByteArray());
        InputStream is2 = new ByteArrayInputStream(out2.toByteArray());
        InputStream[] inputStreams3 = new InputStream[]{is1, is2};

        String[] names3 = {"zip1.zip", "zip2.zip"};

        ByteArrayOutputStream out3 = new ByteArrayOutputStream();
        // 压缩文件
        ZipUtil.zip(out3, names3, inputStreams3);

        //将压缩后的数据写入文件或者作为流传输
        FileOutputStream fos = new FileOutputStream(zipAllPath);
        out3.writeTo(fos);
        fos.close();

        System.out.println("结束!!!");



    }


    @PostMapping("/delete")
    @ApiOperation(value = "批量删除", notes = "删除产品结果", httpMethod = "POST")
    public AjaxResult deleteBatch(@RequestBody List<Long> ids) {
        resultSaveService.removeBatchByIds(ids);
        return AjaxResult.success();
    }

}
